﻿using LxBasic;
using System.Threading;

namespace LxCore
{
    public class SIMPLEFields : ZoneHead
    {
        public SIMPLEPressure Pressure;
        public SIMPLEVelocity Velocity;
        public SIMPLEMass MassFlux;
        public BoundHead[] SimpleBounds;
        protected double[] V_InnFaceShare;
        protected double[] V_BouFaceShare;
        protected double[] W_InnFaceShare;
        protected double[] W_BouFaceShare;
        //public StateArray<bool> IsPressureInOut;//如果压力出口有回流，需要一个系数，这里记录系数有没有初始化

        public IField<double> Density;
        public override void CheckCreate(FvZone zone)
        {
            base.CheckCreate(zone);
            CheckCreator.ArrayStrict(ref SimpleBounds, zone.Bounds.Count);
            CheckCreator.Instance(ref Pressure);
            CheckCreator.Instance(ref Velocity);
            CheckCreator.Instance(ref MassFlux);
            Pressure.CheckCreate(zone);
            Velocity.CheckCreate(zone);
            MassFlux.CheckCreate(zone);
            Pressure.InSimpleFields = this;
            Velocity.InSimpleFields = this;
            MassFlux.SimpleGroup = this;
            CheckCreator.ArrayStrict(ref V_InnFaceShare, Math.Max(zone.InnCells.Length, zone.InnFaces.Length));
            CheckCreator.ArrayStrict(ref V_BouFaceShare, zone.BouFaces.Length);
            CheckCreator.ArrayStrict(ref W_InnFaceShare, zone.InnFaces.Length);
            CheckCreator.ArrayStrict(ref W_BouFaceShare, zone.BouFaces.Length);
            Velocity.V.InnFaceShare = V_InnFaceShare;
            Velocity.V.BouFaceShare = V_BouFaceShare;
            Velocity.W.InnFaceShare = W_InnFaceShare;
            Velocity.W.BouFaceShare = W_BouFaceShare;
            Pressure.InnX_LastStep = V_InnFaceShare;
            Pressure.BouX_LastStep = V_BouFaceShare;
            //if (IsPressureInOut == null || IsPressureInOut.Length != zone.Bounds.Count)
            //{
            //    IsPressureInOut = new StateArray<bool>(zone.Bounds.Count);
            //}
        }
        public void SetZone(IField<double> density)
        {
            this.Density = density;
        }
        public void SetBoundary_NoSlipStaticWall(FvBound bound)
        {
            SetBoundary_NoSlipMovingWall(ConstField.Vector0, bound);
        }
        public void SetBoundary_NoSlipMovingWall(IField<Vector3d> boundaryVelocity, FvBound bound)
        {
            CheckCreator.Instance(ref SimpleBounds[bound.ID], out NoSlipWall b);
            b.SetParameter(bound, boundaryVelocity);

            Velocity.U.SetBound_Symmetry(bound);
            Velocity.V.SetBound_Symmetry(bound);
            Velocity.W.SetBound_Symmetry(bound);
            //IsPressureInOut[bound.ID] = false;
        }
        public void SetBoundary_SlipWall(FvBound bound)
        {
            CheckCreator.Instance(ref SimpleBounds[bound.ID], out Symmetry b);
            b.SetParameter(bound);
            //
            Velocity.U.SetBound_FixValueWall(null, bound);
            Velocity.V.SetBound_FixValueWall(null, bound);
            Velocity.W.SetBound_FixValueWall(null, bound);
            //Velocity.U.SetBound_Symmetry(thread);
            //Velocity.V.SetBound_Symmetry(thread);
            //Velocity.W.SetBound_Symmetry(thread);
            //IsPressureInOut[bound.ID] = false;
        }
        public void SetBound_VelocityInlet(IField<double> value, FvBound bound)//方向垂直壁面指向域内
        {
            SetBound_VelocityInlet(new BouScalarToVectorField(value, Zone), bound);
        }
        public void SetBound_VelocityInlet(IField<Vector3d> value3d, FvBound bound)
        {
            CheckCreator.Instance(ref SimpleBounds[bound.ID], out VelocityInlet b);
            b.SetParameter(bound, value3d);

            Velocity.U.SetBound_FlowValue(null, bound);
            Velocity.V.SetBound_FlowValue(null, bound);
            Velocity.W.SetBound_FlowValue(null, bound);
            //IsPressureInOut[bound.ID] = false;
        }
        public void SetBound_PressureInOut(IField<double> pressure, FvBound thread)//方向垂直壁面指向域内
        {
            SetBound_PressureInOut(pressure, new FaceNormalField(), thread);
        }
        public void SetBound_PressureInOut(IField<double> pressure, IField<Vector3d> direction, FvBound bound)
        {
            CheckCreator.Instance(ref SimpleBounds[bound.ID], out PressureInOut b);
            b.SetParameter(bound, pressure, direction);

            Velocity.U.SetBound_FlowValue(null, bound);
            Velocity.V.SetBound_FlowValue(null, bound);
            Velocity.W.SetBound_FlowValue(null, bound);
            //IsPressureInOut[bound.ID] = true;
        }
        public override void FromJsonKV(string key, IJsonReader jsReader)
        {
            switch (key)
            {
                case nameof(Pressure): jsReader.ReadObject(Pressure, e => Pressure = e, (t) => new SIMPLEPressure()); break;
                case nameof(Velocity): jsReader.ReadObject(Velocity, e => Velocity = e, t => new SIMPLEVelocity()); break;
                case nameof(MassFlux): jsReader.ReadObject(MassFlux, e => MassFlux = e, t => new SIMPLEMass()); break;
                default: base.FromJsonKV(key, jsReader); break;
            }

        }
        public override void ToJsonKV(IJsonWriter jsWriter)
        {
            base.ToJsonKV(jsWriter);
            jsWriter.WriteObject(nameof(Pressure), Pressure);
            jsWriter.WriteObject(nameof(Velocity), Velocity);
            jsWriter.WriteObject(nameof(MassFlux), MassFlux);
        }
        #region boundaryTypes
        public class ZeroMassFlux : BoundHead
        {
            //public ToDoState SetFluxState { get; set; } = new ToDoState(true);
            public Vector2d[] FactorsForPressure;
        }
        public class NoSlipWall : ZeroMassFlux
        {
            public IField<Vector3d> BoundVelocity;
            //public ToDoState SetVelState { get; set; }
            public void SetParameter(FvBound bound, IField<Vector3d> boundaryVelocity)
            {
                this.BoundVelocity = boundaryVelocity;
                CheckCreator.ArrayStrict(ref FactorsForPressure, bound.FaceIdx.GetCount());

                //SetVelState = new ToDoState(boundaryVelocity.IsParameter(out Vector3d _));
            }
        }
        public class Symmetry : ZeroMassFlux
        {
            public void SetParameter(FvBound bound)
            {
                CheckCreator.ArrayStrict(ref FactorsForPressure, bound.FaceIdx.GetCount());
            }
        }
        public class VelocityInlet : BoundHead
        {
            public Vector2d[] FactorsForPressure;
            public IField<Vector3d> Velocity { get; private set; }
            //public ToDoState SetVelState { get; set; }
            public void SetParameter(FvBound bound, IField<Vector3d> velocity)
            {
                this.Velocity = velocity;
                CheckCreator.ArrayStrict(ref FactorsForPressure, bound.FaceIdx.GetCount());
                //SetVelState = new ToDoState(velocity.IsParameter(out var _));
            }
        }
        public class PressureInOut : BoundHead
        {
            public IField<double> Pressure { get; private set; }
            public IField<Vector3d> Direction { get; private set; }//不需要为单位向量
            //public ToDoState SetPressureState;
            public Vector3d[] Factors;//出口时，0梯度要提前计算好系数
            public double[] MassDistributeFactor;//如果流入，则将massImb分给边界面的比例
            public void SetParameter(FvBound b, IField<double> Pressure, IField<Vector3d> Direction)
            {
                this.Pressure = Pressure;
                this.Direction = Direction;
                CheckCreator.ArrayStrict(ref Factors, b.FaceIdx.GetCount());
                CheckCreator.ArrayStrict(ref MassDistributeFactor, b.FaceIdx.GetCount());
                //SetPressureState = new ToDoState(Pressure.IsParameter(out double _));
            }
        }
        public class BouScalarToVectorField : FieldBase<Vector3d>
        {
            public BouScalarToVectorField(IField<double> value, FvZone zone)
            {
                this.value = value;
                this.zone = zone;
            }
            FvZone zone;
            IField<double> value;
            public override ICellVarArr<Vector3d> GetCellVarArr(IIndexHost indexHost)
            {
                return new BoundVel()
                {
                    BouFaces = zone.BouFaces,
                    cellVel = value.GetCellVarArr(indexHost),
                };
            }
            public override IFaceVarArr<Vector3d> GetFaceVarArr(IIndexHost indexHost)
            {
                return new BoundVel()
                {
                    BouFaces = zone.BouFaces,
                    faceVel = value.GetFaceVarArr(indexHost),
                };
            }
            public struct BoundVel : ICellVarArr<Vector3d>, IFaceVarArr<Vector3d>
            {
                public FvBouFace[] BouFaces;
                public ICellVarArr<double> cellVel;
                public IFaceVarArr<double> faceVel;
                public Vector3d GetCellVar(int cellID)
                {
                    ref var bouFace = ref BouFaces[cellID];
                    return -cellVel.GetCellVar(cellID) / bouFace.Area * bouFace.Normal;
                }
                public Vector3d GetFaceVar(int faceID)
                {
                    ref var bouFace = ref BouFaces[faceID];
                    return -faceVel.GetFaceVar(faceID) / bouFace.Area * bouFace.Normal;
                }
            }
        }
        #endregion
    }

}
